package de.lgohlke.compress;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * ValueObjects which keeps original values, when compression does not save space
 *
 * @author lars
 * @param <T>
 * @version $Id: $
 */
public class CompressableValue<T>
{
  private final byte[]  raw;
  private final T       value;
  private final boolean compressed;

  /**
   * <p>Constructor for CompressableValue.</p>
   *
   * @param value a T object.
   * @param compressed a boolean.
   * @param raw an array of byte.
   * @param <T> a T object.
   */
  public CompressableValue(final T value, final boolean compressed, final byte[] raw)
  {
    this.value = value;
    this.compressed = compressed;
    this.raw = raw;
  }

  /**
   * <p>Constructor for CompressableValue.</p>
   *
   * @param value a T object.
   * @param compressed a boolean.
   */
  public CompressableValue(final T value, final boolean compressed)
  {
    this(value, compressed, null);
  }

  /**
   * <p>Getter for the field <code>value</code>.</p>
   *
   * @return a T object.
   */
  public T getValue()
  {
    return value;
  }

  /**
   * <p>isCompressed.</p>
   *
   * @return a boolean.
   */
  public boolean isCompressed()
  {
    return compressed;
  }

  /** {@inheritDoc} */
  @Override
  public String toString()
  {
    StringBuffer b = new StringBuffer();

    b.append(this.getClass().getSimpleName());
    b.append('(');
    b.append(value.getClass().getSimpleName());
    b.append(',');
    b.append("compressed:");
    b.append(isCompressed());
    b.append(')');
    b.append('\n');
    b.append(value.toString());
    b.append('\n');

    return b.toString();
  }

  /** {@inheritDoc} */
  @Override
  public int hashCode()
  {
    return new HashCodeBuilder().append(compressed).append(value).toHashCode();
  }

  /** {@inheritDoc} */
  @Override
  public boolean equals(final Object obj)
  {
    if (obj == null)
    {
      return false;
    }

    if (obj == this)
    {
      return true;
    }

    if (obj.getClass() != getClass())
    {
      return false;
    }

    @SuppressWarnings("unchecked")
    CompressableValue<T> cv = (CompressableValue<T>) obj;
    T _value = cv.getValue();
    if ((_value != null) && (_value.getClass() != value.getClass()))
    {
      return false;
    }

    if (cv.isCompressed() != isCompressed())
    {
      return false;
    }

    return new EqualsBuilder().//
        append(value, _value). //
        append(raw, cv.getRaw()). //
        isEquals();
  }

  /**
   * <p>Getter for the field <code>raw</code>.</p>
   *
   * @return an array of byte.
   */
  public byte[] getRaw()
  {
    return raw == null ? null : raw.clone();
  }
}
